1 using UnityEngine;
2 using
System.Collections;
3
4 public
class ThirdPersonCamera : MonoBehaviour
5 {
6
7     
public Transform cameraTransform;
8     
private Transform _target;
9
10     
// The distance in the x-z plane to the target
11
12     
public float distance = 7.0f;
13
14     
// the height we want the camera to be above the target
15     
public float height = 3.0f;
16
17     
public float angularSmoothLag = 0.3f;
18     
public float angularMaxSpeed = 15.0f;
19
20     
public float heightSmoothLag = 0.3f;
21
22     
public float snapSmoothLag = 0.2f;
23     
public float snapMaxSpeed = 720.0f;
24
25     
public float clampHeadPositionScreenSpace = 0.75f;
26
27     
public float lockCameraTimeout = 0.2f;
28
29     
private Vector3 headOffset = Vector3.zero;
30     
private Vector3 centerOffset = Vector3.zero;
31
32     
private float heightVelocity = 0.0f;
33     
private float angleVelocity = 0.0f;
34     
private bool snap = false;
35     
private ThirdPersonController controller;
36     
private float targetHeight = 100000.0f;
37
38     
private Camera m_CameraTransformCamera;
39
40     
void OnEnable()
41     {
42         
if( !cameraTransform && Camera.main )
43             cameraTransform = Camera.main.transform;
44         
if( !cameraTransform )
45         {
46             Debug.Log(
"Please assign a camera to the ThirdPersonCamera script." );
47             enabled =
false;
48         }
49
50         m_CameraTransformCamera = cameraTransform.GetComponent<Camera>();
51
52         _target = transform;
53         
if( _target )
54         {
55             controller = _target.GetComponent<ThirdPersonController>();
56         }
57
58         
if( controller )
59         {
60             CharacterController characterController = (CharacterController)_target.GetComponent<Collider>();
61             centerOffset = characterController.bounds.center - _target.position;
62             headOffset = centerOffset;
63             headOffset.y = characterController.bounds.max.y - _target.position.y;
64         }
65         
else
66             Debug.Log(
"Please assign a target to the camera that has a ThirdPersonController script attached." );
67
68
69         Cut( _target, centerOffset );
70     }
71
72     
void DebugDrawStuff()
73     {
74         Debug.DrawLine( _target.position, _target.position + headOffset );
75
76     }
77
78     
float AngleDistance( float a, float b )
79     {
80         a = Mathf.Repeat( a,
360 );
81         b = Mathf.Repeat( b,
360 );
82
83         
return Mathf.Abs( b - a );
84     }
85
86     
void Apply( Transform dummyTarget, Vector3 dummyCenter )
87     {
88         
// Early out if we don't have a target
89         
if( !controller )
90             
return;
91
92         Vector3 targetCenter = _target.position + centerOffset;
93         Vector3 targetHead = _target.position + headOffset;
94
95         
// DebugDrawStuff();
96
97         
// Calculate the current & target rotation angles
98         
float originalTargetAngle = _target.eulerAngles.y;
99         
float currentAngle = cameraTransform.eulerAngles.y;
100
101         
// Adjust real target angle when camera is locked
102         
float targetAngle = originalTargetAngle;
103
104         
// When pressing Fire2 (alt) the camera will snap to the target direction real quick.
105         
// It will stop snapping when it reaches the target
106         
if( Input.GetButton( "Fire2" ) )
107             snap =
true;
108
109         
if( snap )
110         {
111             
// We are close to the target, so we can stop snapping now!
112             
if( AngleDistance( currentAngle, originalTargetAngle ) < 3.0f )
113                 snap =
false;
114
115             currentAngle = Mathf.SmoothDampAngle( currentAngle, targetAngle,
ref angleVelocity, snapSmoothLag, snapMaxSpeed );
116         }
117         
// Normal camera motion
118         
else
119         {
120             
if( controller.GetLockCameraTimer() < lockCameraTimeout )
121             {
122                 targetAngle = currentAngle;
123             }
124
125             
// Lock the camera when moving backwards!
126             
// * It is really confusing to do 180 degree spins when turning around.
127             
if( AngleDistance( currentAngle, targetAngle ) > 160 && controller.IsMovingBackwards() )
128                 targetAngle +=
180;
129
130             currentAngle = Mathf.SmoothDampAngle( currentAngle, targetAngle,
ref angleVelocity, angularSmoothLag, angularMaxSpeed );
131         }
132
133
134         
// When jumping don't move camera upwards but only down!
135         
if( controller.IsJumping() )
136         {
137             
// We'd be moving the camera upwards, do that only if it's really high
138             
float newTargetHeight = targetCenter.y + height;
139             
if( newTargetHeight < targetHeight || newTargetHeight - targetHeight > 5 )
140                 targetHeight = targetCenter.y + height;
141         }
142         
// When walking always update the target height
143         
else
144         {
145             targetHeight = targetCenter.y + height;
146         }
147
148         
// Damp the height
149         
float currentHeight = cameraTransform.position.y;
150         currentHeight = Mathf.SmoothDamp( currentHeight, targetHeight,
ref heightVelocity, heightSmoothLag );
151
152         
// Convert the angle into a rotation, by which we then reposition the camera
153         Quaternion currentRotation = Quaternion.Euler(
0, currentAngle, 0 );
154
155         
// Set the position of the camera on the x-z plane to:
156         
// distance meters behind the target
157         cameraTransform.position = targetCenter;
158         cameraTransform.position += currentRotation * Vector3.back * distance;
159
160         
// Set the height of the camera
161         cameraTransform.position =
new Vector3( cameraTransform.position.x, currentHeight, cameraTransform.position.z );
162
163         
// Always look at the target
164         SetUpRotation( targetCenter, targetHead );
165     }
166
167     
void LateUpdate()
168     {
169         Apply( transform, Vector3.zero );
170     }
171
172     
void Cut( Transform dummyTarget, Vector3 dummyCenter )
173     {
174         
float oldHeightSmooth = heightSmoothLag;
175         
float oldSnapMaxSpeed = snapMaxSpeed;
176         
float oldSnapSmooth = snapSmoothLag;
177
178         snapMaxSpeed =
10000;
179         snapSmoothLag =
0.001f;
180         heightSmoothLag =
0.001f;
181
182         snap =
true;
183         Apply( transform, Vector3.zero );
184
185         heightSmoothLag = oldHeightSmooth;
186         snapMaxSpeed = oldSnapMaxSpeed;
187         snapSmoothLag = oldSnapSmooth;
188     }
189
190     
void SetUpRotation( Vector3 centerPos, Vector3 headPos )
191     {
192         
// Now it's getting hairy. The devil is in the details here, the big issue is jumping of course.
193         
// * When jumping up and down we don't want to center the guy in screen space.
194         
// This is important to give a feel for how high you jump and avoiding large camera movements.
195         
//
196         
// * At the same time we dont want him to ever go out of screen and we want all rotations to be totally smooth.
197         
//
198         
// So here is what we will do:
199         
//
200         
// 1. We first find the rotation around the y axis. Thus he is always centered on the y-axis
201         
// 2. When grounded we make him be centered
202         
// 3. When jumping we keep the camera rotation but rotate the camera to get him back into view if his head is above some threshold
203         
// 4. When landing we smoothly interpolate towards centering him on screen
204         Vector3 cameraPos = cameraTransform.position;
205         Vector3 offsetToCenter = centerPos - cameraPos;
206
207         
// Generate base rotation only around y-axis
208         Quaternion yRotation = Quaternion.LookRotation(
new Vector3( offsetToCenter.x, 0, offsetToCenter.z ) );
209
210         Vector3 relativeOffset = Vector3.forward * distance + Vector3.down * height;
211         cameraTransform.rotation = yRotation * Quaternion.LookRotation( relativeOffset );
212
213         
// Calculate the projected center position and top position in world space
214         Ray centerRay = m_CameraTransformCamera.ViewportPointToRay(
new Vector3( 0.5f, 0.5f, 1 ) );
215         Ray topRay = m_CameraTransformCamera.ViewportPointToRay(
new Vector3( 0.5f, clampHeadPositionScreenSpace, 1 ) );
216
217         Vector3 centerRayPos = centerRay.GetPoint( distance );
218         Vector3 topRayPos = topRay.GetPoint( distance );
219
220         
float centerToTopAngle = Vector3.Angle( centerRay.direction, topRay.direction );
221
222         
float heightToAngle = centerToTopAngle / ( centerRayPos.y - topRayPos.y );
223
224         
float extraLookAngle = heightToAngle * ( centerRayPos.y - centerPos.y );
225         
if( extraLookAngle < centerToTopAngle )
226         {
227             extraLookAngle =
0;
228         }
229         
else
230         {
231             extraLookAngle = extraLookAngle - centerToTopAngle;
232             cameraTransform.rotation *= Quaternion.Euler( -extraLookAngle,
0, 0 );
233         }
234     }
235
236     Vector3 GetCenterOffset()
237     {
238         
return centerOffset;
239     }
240
241 }


The distance in the x-z plane to the target

the height we want the camera to be above the target

Early out if we don't have a target

DebugDrawStuff();

Calculate the current & target rotation angles

Adjust real target angle when camera is locked

When pressing Fire2 (alt) the camera will snap to the target direction real quick.

It will stop snapping when it reaches the target

We are close to the target, so we can stop snapping now!

Normal camera motion

Lock the camera when moving backwards!

* It is really confusing to do 180 degree spins when turning around.

When jumping don't move camera upwards but only down!

We'd be moving the camera upwards, do that only if it's really high

When walking always update the target height

Damp the height

Convert the angle into a rotation, by which we then reposition the camera

Set the position of the camera on the x-z plane to:

distance meters behind the target

Set the height of the camera

Always look at the target

Now it's getting hairy. The devil is in the details here, the big issue is jumping of course.

* When jumping up and down we don't want to center the guy in screen space.

This is important to give a feel for how high you jump and avoiding large camera movements.

* At the same time we dont want him to ever go out of screen and we want all rotations to be totally smooth.

So here is what we will do:

1. We first find the rotation around the y axis. Thus he is always centered on the y-axis

2. When grounded we make him be centered

3. When jumping we keep the camera rotation but rotate the camera to get him back into view if his head is above some threshold

4. When landing we smoothly interpolate towards centering him on screen

Generate base rotation only around y-axis

Calculate the projected center position and top position in world space




Trò chơi Tic-Tac-Toe, game đánh caro full source code 53.507 lượt xem

Gõ tìm kiếm nhanh...